const PENDING='pending'
const FULFILLED='fulfilled'
const REJECTED='rejected'

class MyPromise{
    constructor(executor){
        try {
            executor(this.resolve,this.reject)
        } catch (error) {
            this.reject(error)
        }
        
    }
    Status=PENDING
    value=undefined
    reason=undefined
    successCallback=[]
    failCallback=[]
    resolve=value=>{
        if(this.Status!=PENDING) return
        this.Status=FULFILLED
        this.value=value
        while (this.successCallback.length) this.successCallback.shift()()
    }
    reject=reason=>{
        if(this.Status!=PENDING)return
        this.Status=REJECTED
        this.reason=reason
        while (this.failCallback.length) this.failCallback.shift()()
    }
    then(successCallback,failCallback){
        successCallback=successCallback?successCallback:value=>value
        failCallback=failCallback?failCallback:reason=>{throw reason}
        let promise2=new MyPromise((resolve,reject)=>{
            if(this.Status==FULFILLED){
                try {
                    setTimeout(()=>{
                        let x = successCallback(this.value)
                        // 判断 x 是普通值还是promise对象
                        // 普通值：直接调用resolve
                        // promise对象： 查看promise对象返回的结果，再根据返回的结果决定调用resolve还是reject
                        resolvePromise(promise2,x,resolve,reject)
                    },0)
                } catch (error) {
                    this.reject(error)
                }
            }else if(this.Status==REJECTED){
                
                try {
                    setTimeout(()=>{
                        let x = failCallback(this.reason)
                    // 判断 x 是普通值还是promise对象
                    // 普通值：直接调用resolve
                    // promise对象： 查看promise对象返回的结果，再根据返回的结果决定调用resolve还是reject
                    resolvePromise(promise2,x,resolve,reject)
                    },0)
                } catch (error) {
                    this.reject(error)
                }
            }else{
                //等待状态
                this.failCallback.push(()=>{
                    try {
                        setTimeout(()=>{
                            let x = failCallback(this.reason)
                        // 判断 x 是普通值还是promise对象
                        // 普通值：直接调用resolve
                        // promise对象： 查看promise对象返回的结果，再根据返回的结果决定调用resolve还是reject
                        resolvePromise(promise2,x,resolve,reject)
                        },0)
                    } catch (error) {
                        this.reject(error)
                    }
                })
                this.successCallback.push(()=>{
                    try {
                        setTimeout(()=>{
                            let x = successCallback(this.value)
                        // 判断 x 是普通值还是promise对象
                        // 普通值：直接调用resolve
                        // promise对象： 查看promise对象返回的结果，再根据返回的结果决定调用resolve还是reject
                        resolvePromise(promise2,x,resolve,reject)
                        },0)
                    } catch (error) {
                        this.reject(error)
                    }
                })
            }
        })
        return promise2
    }
    finally(callback){
        return this.then(value=>{
            return MyPromise.resolve(callback()).then(()=>value)
        },reason=>{
            return MyPromise.resolve(callback()).then(()=>{throw reason})
        })
    }
    catch(callback){
        return this.then(undefined,callback)
    }
    static all(array){
        let result=[]
        let resultCompletedCount=0
        return new MyPromise((resolve,reject)=>{
            function AddResult(index,value){
                result[index]=value
                resultCompletedCount++
                if(resultCompletedCount==array.length){
                    resolve(result)
                }
            }
            for(let i =0;i<array.length;i++){
                let current=array[i]
                if(current instanceof MyPromise){
                    current.then(value=>AddResult(i,value),reason=>reject(reason))
                }else{
                    AddResult(i,array[i])
                }
            }
        })
    }
    static resolve(value){
        if(value instanceof MyPromise) return value
        else{
            return new MyPromise((resolve)=>{
                resolve(value)
            })
        }
    }
}
function resolvePromise(promise2,x,resolve,reject){
    // 识别自调用
    if(promise2===x){
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if(x instanceof MyPromise){
        x.then(resolve,reject)
    }else{
        resolve(x)
    }
}
module.exports=MyPromise